#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
#include <semaphore.h>
#include "param.h"
#include "types.h"
#include "defs.h"

int
filebuf_ring_init (filebuf_ring *ring) {
    if (pthread_mutex_init(&(ring->mtx), NULL) == -1)
        HANDLE_ERROR ("buf_ring_init", "ring->mtx",1);
    ring->elem_num = 0;
    ring->head = NULL;
    ring->tail = NULL;
    return 0;
    error:
    return -1;
}

filebuf *
filebuf_ring_get (filebuf_ring *ring, enum fb_type btype) {
    ring_node *rn, *next, *prev;
    filebuf *fb;
    int i;
    if (ring == NULL)
        HANDLE_ERROR ("buf_ring_get","ring",0);
    LOCK (ring->mtx);
    #ifdef DEBUG
    printf ("ring checking head:\n");
    filebuf *ptr; 
    ptr = ring->tail;
    for (i = 0; i < ring->elem_num; i++) {
        printf("[%d]%d ",i, ptr->type);
        ptr = ptr->next;
    }
    printf ("\n");
    #endif
    rn = ring->head;
    if (rn == NULL)
        goto none;
    for (i = 0; i < ring->elem_num; i++) {
        if (rn->fbuf->type == btype) {
            if (ring->elem_num > 1) {
                prev = rn->prev;
                next = rn->next;
                prev->next = next;
                next->prev = prev;
                ring->head = next;
                if (ring->tail == rn) {
                    ring->tail = prev;
                }
            } else {
                ring->head = NULL;
                ring->tail = NULL;
            }
            ring->elem_num--;
            goto find;
        }
        rn = rn->next;
    }
    goto none;
    find:
    UNLOCK (ring->mtx);
    fb = rn->fbuf;
    free (rn);
    return fb;
    none:
    UNLOCK (ring->mtx);
    return NULL;
    error:
    return NULL;
}

int
filebuf_ring_put (filebuf_ring *ring, filebuf *fbuf) {
    ring_node *rn, *next, *prev;
    if (ring == NULL || fbuf == NULL)
        HANDLE_ERROR ("filebuf_ring_put","ring&fbuf",0);
    if ((rn = malloc (sizeof (ring_node))) == NULL)
        HANDLE_ERROR ("filebuf_ring_put","rn",1);
    LOCK (ring->mtx);
    #ifdef DEBUG
    printf ("ring checking tail:\n");
    filebuf *ptr; int i;
    ptr = ring->tail;
    for (i = 0; i < ring->elem_num; i++) {
        printf("[%d]%d ",i, ptr->type);
        ptr = ptr->next;
    }
    printf ("\n");
    #endif
    rn->fbuf = fbuf;
    if (ring->elem_num == 0) {
        rn->prev = rn;
        rn->next = rn;
        ring->head = rn;
        ring->tail = rn;
    } else {
        prev = ring->tail;
        next = ring->tail->next;
        prev->next = rn;
        next->prev = rn;
        rn->next = next;
        rn->prev = prev;
        ring->tail = rn;
    }
    ring->elem_num++;
    UNLOCK (ring->mtx);
    return 0;
    error:
    return -1;
}
